# -*- coding: utf-8 -*-
## ******************************************************************* GLWIDGET.PY
## * Description:
## * The code contained in this file is meant to handle all the elements
## * (events, routines and classes) that exist in the glwidget canvas.
## *******************************************************************************
## * Created in: 07-01-07
## * Last updated in: 03-13-08
## *******************************************************************************
## * Authoring: Elisabete Thomaselli Nogueira and Victor S. Bursztyn
## * Orientation: Claudio Esperanca
## *******************************************************************************
#import sys ##2008-05-06
#import os  ##2008-05-06
from PyQt4 import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *

try:
  from OpenGL.GL import *
  from OpenGL.GLU import *
except:
  print '''ERROR: PyOpenGL not installed properly.'''
  sys.exit(1)

from PyQt4.QtOpenGL import *

## *******************************************************************************
import cPickle            #In order to save presentations
from scipy import *
from threading import Timer
from math import *
## *******************************************************************************
## * Importing complementary code contained in other self-explained files.
## *******************************************************************************

from animations import *
import Image            #In order to handle textures

from arcball import *

#from BoundingBox import *
#from EditableVisualElement import *
from scene import *

##*******************************************************************************
# Load Documentation Image
##*******************************************************************************
def loadImage(path):

    """Loads an image from a file.
    @param imageName: path to the actual image file.
    @return: ID of the new allocated texture.
    """

    """Load an image file as a 2D texture using PIL
    This method combines all of the functionality required to load the image with PIL, convert it
    to a format compatible with PyOpenGL, generate the texture ID, and store the image data under
    that texture ID.
    Note: only the ID is returned, no reference to the image object or the string data is
    stored in user space, the data is only present within the OpenGL engine after this call exits.
    """
    im = Image.open(path)
    #im.transpose(Image.FLIP_TOP_BOTTOM)
    try:
        ## get image meta-data (dimensions) and data
        ix, iy, image = im.size[0], im.size[1], im.tostring()
    except SystemError:
        ## has no alpha channel, synthesize one, see the
        ## texture module for more realistic handling
        ix, iy, image = im.size[0], im.size[1], im.tostring()
        ## generate a texture ID
        ID = glGenTextures(1)
        ## make it current
        glBindTexture(GL_TEXTURE_2D, ID)
        #glPixelStorei(GL_UNPACK_ALIGNMENT,1)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
        ## return the ID for use
        return ID

##*******************************************************************************
## * Classe txtNote() deve ser revista ap?s as novas considera??es feitas
## * no conceito de documenta??o.
## *******************************************************************************
"""class txtNote():

    def __init__(self):
    ## Textual note constructor.
    ## Whenever a text comment is associated to a model, a txtNote instance is added to this model's txtNotes list.
    ## The description is saved to an automatically generated *.bmp file, which is loaded through loadImage(), generating
    ## the proper ID for the texture.
    ## ****************************************************************************************
    ## DocumentationDialog -> txtNote.bmp -> txtNote instance -> part of model's txtNotes list
    ## ****************************************************************************************
    return"""

## *******************************************************************************
class glWidget(QGLWidget):

    sceneElements = [] ## List of models contained in the current scene

    def __init__(self, parent=None, Width = 640, Height = 480, animType = None,  playerExit = 1,  firstFrame = 1, lastFrame = 100, Running = True,  fps = 10):
        """Constructor"""
        super (glWidget, self).__init__(parent)
        self.motionfunc = self.defaultMouseMoveEvent

        QGLWidget.setMouseTracking(self, 1)
        self.enable_wheel = True
        self.Width = Width
        self.Height = Height

        self.selectedModel = -1
        self.selectedGroup = -1

        #self.setSelected(True)    ## cut, copy
        self.setFocusPolicy(QtCore.Qt.StrongFocus) ## Ativate wheel in keyPress

        ##?? Tem ??  Initializes all transformations needed to the ArcBall routine
        self.r_isDragging = False



        #*******************************************************
        # Default transformation parameters
        #*******************************************************
        self.sx, self.sy, self.sz = 1.0, 1.0, 1.0     ## The default is not to scale
        self.tx, self.ty, self.tz = 0, 0, 0             ## The default is not to translate
        self.lastpt = [0, 0, 0]                           ## The previous point coordenate in the openGL screen
        self.newpt  = [0, 0, 0]                           ## The current point coordenate in the openGL screen
        #self.lastpt = [0, 0]    ##m             ## The previous point coordenate in the screen
        #self.newpt  = [0, 0]                 ## The current point coordenate in the screen

        self.side = (0.1, 0.1, 0.1)

        #*******************************************************
        # Default animation display parameters
        #*******************************************************
        self.firstFrame = firstFrame
        self.frameCount = firstFrame
        self.fps = fps
        self.lastFrame = lastFrame
        self.nframes = self.lastFrame - self.firstFrame + 1 ## VER LOCAL CORRETO
        self.Running = True

        self.playerExit = playerExit

       ## gluPerspective parameters
        self.fovy = 80
        self.zNear = 2 #0.1
        self.zFar  = -5   #500

        ##FUTURA REFERENCIA - tornar os parametros de camera editaveis pela aplicacao.
        self.eyeX = 0.0
        self.eyeY = 0.0
        self.eyeZ = 3.0
        self.centerX = 0.0
        self.centerY = 0.0
        self.centerZ = 0.0
        self.upX = 0.0
        self.upY = 1.0
        self.upZ = 0.0

        ##FUTURA REFERENCIA - tornar as luzes da cena editaveis pela aplicacao.
        self. lamb = [1.0, 1.0, 1.0, 0.1]
        self.ldif = [1.0, 1.0, 1.0, 1.0]
        self.lspec = [0.5, 0.5, 0.5, 0.1]
        self.lpos = [-1.0, 3.0, 1.0, 1.0]
        self.lmod_amb = [1.0, 1.0, 1.0, 1.0]
        self.sceneRenderSetUp()

    def paintEvent(self, event):

        painter = QtGui.QPainter()
        painter.begin(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)

        self.drawScene(False)

        painter.end()

    def resizeGL (self, width, height):
        """A simple resize callback."""
        """
        Resizes the window, sets a new vieport and a new perspetive transformation.
        """
        if width < 2 or height < 2:     ##? To avoid ZeroDivisionError. It must be 2 because arcball subtracts 1
           return
        self.width,self.height = width,height

        self.screencenter = (width/2.0, height/2.0, 0.0)  ## Inicialize scene center as windows center.

        glViewport (0, 0, width, height);
        glMatrixMode (GL_PROJECTION);
        glLoadIdentity()
        glOrtho (0, width, 0, height, -1000, 1000)
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity()
        ##1 self.centerscene()


    def initializeGL(self):
        self.newCursorModel()               ## Includes a 3D Cursor in the scene.
        self.sceneRenderSetUp()

    def sceneRenderSetUp(self):
        """ This routine defines scene aspects.
        * gluPerspective - define a view frustum
        @param fovy:  Specifies the field of view angle, in    degrees, in the y direction.
        @param aspect:Specifies the aspect ratio that determines the field of view in the x direction.
            The aspect ratio is the ratio of x (width) to y (height).
        @param zNear: Specifies the distance from the viewer to the    near clipping plane (always positive).
        @param zFar:  Specifies the distance from the viewer to the    far clipping plane (always positive).
        * gluLookAt - define a viewing transformation
        @param eyeX: Specifies the    position of the    eye point.
        @param eyeY:
        @param eyeZ:
        @param centerX: Specifies the position of the reference point.
        @param centerY:
        @param centerZ:
        @param upX: Specifies the direction of the up vector.
        @param upY:
        @param upZ:"""

        glMatrixMode(GL_PROJECTION)             #err pyqt4.3 24-03
        glLoadIdentity()

        aspect = self.Width/self.Height
        ## *************************************************************************************
        ## * gluPerspective specifies a viewing frustum into the world coordinate system.
        ## * In general, the aspect ratio in gluPerspective should match the aspect ratio of the associated viewport.
        ## *************************************************************************************
        gluPerspective(self.fovy, aspect, self.zNear, self.zFar)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        ## *************************************************************************************
        ## * gluLookAt creates a viewing matrix derived from an eye point, a reference point indicating the center of the
        ## * scene, and an UP vector.
        ## *************************************************************************************
        gluLookAt(self.eyeX, self.eyeY, self.eyeZ, self.centerX,  self.centerY,  self.centerZ, self.upX, self.upY, self.upZ)
        ##glLightfv trata a iluminacao da cena.
        ##glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmod_amb)
        glLightfv(GL_LIGHT0, GL_AMBIENT, self.lamb)
        glLightfv(GL_LIGHT0, GL_DIFFUSE, self.ldif)
        glLightfv(GL_LIGHT0, GL_POSITION, self.lpos)
        glLightfv(GL_LIGHT0, GL_SPECULAR, self.lspec)
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)

        glBlendFunc(GL_SRC_ALPHA, GL_ONE)

        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_NORMALIZE)
        glShadeModel(GL_SMOOTH)
        glEnable(GL_COLOR_MATERIAL)
        glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT)

        glClearColor(0.25,0.25,0.25,1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def drawScene(self, testSelection = False):

        glMatrixMode(GL_MODELVIEW)
        #Nao funciona no windows. self.autoSave()         ## Salva contexto para undo/redo
        if not testSelection: ##If is not testSelection
            self.sceneRenderSetUp()    # Ja esta no init e no initGL ?? mas precisa disso. Porque?
            for model in self.sceneElements:

                if (model.modelId == self.selectedModel): ##If is selectedModel

                    if (model.copyId != -1): ##If is copy

                        for m in self.sceneElements:
                            if (m.modelId == model.copyId):

                                m.draw(self.selectedGroup, False, model.getTransformationMatrix(), model.getTransformation(), model.getGroupTransformations(), model.getGroupIds(), model.getGroupRGBs())
                                m.box.draw()
                                if self.r_isDragging == True:
                                    self.arcball.draw(model.getTransformationMatrix(), model.getTransformation(), model.box.vertices(), model.objName)

                    else: ##If is not copy

                        model.draw(self.selectedGroup, False, model.getTransformationMatrix(), model.getTransformation(), model.getGroupTransformations(), model.getGroupIds(), model.getGroupRGBs())
                        if self.selectedModel != 0:             ## except for 3DCursor
                            model.box.draw()
                        else:
                            print "3DCursor mustn't have bounding box. self.selectedModel ",  self.selectedModel ##

                        if self.r_isDragging == True:
                                                self.arcball.draw(model.getTransformationMatrix(), model.getTransformation(), model.box.vertices(), model.objName)

                else: ##If is not selectedModel

                    if (model.copyId != -1): ##If is copy

                        for m in self.sceneElements:
                            if (m.modelId == model.copyId):
                                                        m.draw(-1, False, model.getTransformationMatrix(), model.getTransformation(), model.getGroupTransformations(), model.getGroupIds(), model.getGroupRGBs())

                                                        if self.r_isDragging == True:
                                                            self.arcball.draw(model.getTransformationMatrix(), model.getTransformation(), model.box.vertices(), model.objName)

                    else: ##If is not copy

                        model.draw(-1, False, model.getTransformationMatrix(), model.getTransformation(), model.getGroupTransformations(), model.getGroupIds(), model.getGroupRGBs())

                        if self.r_isDragging == True:
                            self.arcball.draw(model.getTransformationMatrix(), model.getTransformation(), model.box.vertices(), model.objName)

        else: ##If is testSelection

            for model in self.sceneElements:

                glPushName(model.modelId)

                if (model.copyId != -1): ##If is copy

                    for m in self.sceneElements:
                        if (m.modelId == model.copyId):
                            m.draw(-1, True, model.getTransformationMatrix(), model.getTransformation(), model.getGroupTransformations(), model.getGroupIds(), model.getGroupRGBs())
                            if self.r_isDragging == True:
                                self.arcball.draw(model.getTransformationMatrix(), model.getTransformation(), model.objName)

                else: ##If is not copy

                    model.draw(-1, True, model.getTransformationMatrix(), model.getTransformation(), model.getGroupTransformations(), model.getGroupIds(), model.getGroupRGBs())

                    if self.r_isDragging == True:
                        self.arcball.draw(model.getTransformationMatrix(), model.getTransformation(), model.objName)
                #os.rename("autosave.step", "undo.step")
                #self.autoSave()         ## Salva contexto para undo/redo
                glPopName()
        #os.rename("autosave.step", "undo.step")
        #self.autoSave()         ## Salva contexto para undo/redo
        glMatrixMode(GL_PROJECTION)

    #*******************************************************
    # Animation routines
    #*******************************************************

    ##VER se precisa
    def timerEvent(self, event):
        if not Running:
            return

    def animateObj(self, animType,  playerExit, initFrame,  lastFrame,  vel, Running):

        self.animType = animType
        self.playerExit = playerExit
        self.firstFrame = initFrame
        self.frameCount = self.firstFrame
        self.lastFrame  = lastFrame
        self.vel        = vel
        self.Running    = Running
        self.nframes    = self.lastFrame - self.firstFrame + 1

        """ According to animation choose in interfAnim window, a group of frames will be interpolated.
        These animations will be played together in a timeline.
        @param anim: animation script"""
        print "animateObj Running ", self.animType, " ",self.Running
        if self.animType == "TransRot":
            self.anim, self.interptrans = anim_TransRot.anim_TransRot(self.firstFrame, self.lastFrame, self.nframes)
            #self.anim, self.interptrans, self.interpolate = self.anim.anim_TransRot()
            ##animation_scripts.anim_TransRot.anim_TransRot(self)   ## Versao futura
            print "self.anim, self.interptrans, self.interpolate ", self.anim, "***", self.interptrans, "***", self.interpolate
        elif self.animType == "bringObj":
            self.anim, self.interptrans = anim_bringObj.anim_bringObj(self.firstFrame, self.lastFrame, self.nframes)
        elif self.animType == "topRight":
            self.anim, self.interptrans = anim_topRight.anim_topRight(self.firstFrame, self.lastFrame, self.nframes)
        elif self.animType == "topLeft":
            self.anim, self.interptrans = self.anim.anim_topLeft(self.firstFrame, self.lastFrame, self.nframes)
        elif self.animType == "botRight":
            self.anim, self.interptrans = self.anim.anim_botRight(self.firstFrame, self.lastFrame, self.nframes)
        elif self.animType == "botLeft":
            self.anim, self.interptrans = self.anim.anim_botLeft(self.firstFrame, self.lastFrame, self.nframes)
            #print "self.anim, self.interptrans, self.interpolate ", self.anim, "***", self.interptrans, "***", self.interpolate

    ##VER se precisa
    def playHandler(self, args):
        self.Running = args

    def scenePause(self, args):
        print "scenePause Running ", self.Running
        self.Running = args

    def setValue(self, value):
        self.horizontalSlider.setValue(value)

    def frameCount(self):
        return self.frameCount

    def playStop(self, args):
        self.playerExit = args

        if self.playerExit == 1:
            print "self.playerExit 1 ", self.playerExit
            self.Running = False
            self.frameCount = self.firstFrame
            self.emit(QtCore.SIGNAL("modelMoved(int)"), self.firstFrame)
            #return
        else:
            print "self.playerExit 2", self.playerExit
            self.Running == False
            #return

    def update2Scene(self,  frame):
        self.frameCount = frame
        self.anim.updateObject (self.frameCount, -1, self.sceneElements)

        #self.repaint()
        #self.update()

    def updateScene(self):  ## Animation procedure
        print "updateScene",  self.Running,  "self.frameCount ",  self.frameCount,  "self.lastFrame ", self.lastFrame

        if self.Running == False:
            return
        if self.frameCount > self.lastFrame:
            return
        if self.playerExit == 0:
            self.Running = False
            self.frameCount = self.firstFrame
            self.emit(QtCore.SIGNAL("modelMoved(int)"), self.firstFrame)
            return

        ## Updates selected object curent position, according to frameCount
        self.anim.updateObject (self.frameCount, -1, self.sceneElements)

        #self.repaint()
        #self.update()
        self.frameCount = self.frameCount + 1
        print "self.frameCount, self.lastFrame ",  self.frameCount, " ",self.lastFrame

        if self.frameCount <= self.lastFrame: ## Ultimo frame da pagina = 200
            self.emit(QtCore.SIGNAL("modelMoved(int)"), self.frameCount)
        else:
            print "sai do updateScene"
            self.emit(QtCore.SIGNAL("quitPlayer(int)"), self.playerExit)

    def scenePause(self, args):
        print "scenePause Running ", self.Running
        self.Running = args

    def plotGraph(self):
        """Plot the animation curve from the current animation keyframe"""
        #import plot

        import numpy
        import pylab
        import matplotlib.axes3d
        #import plot
        #self.plot_frames()
        f = pylab.figure()
        ax = matplotlib.axes3d.Axes3D(f)
        #print "anim ", self.anim
        #ax.plot3D(array([ 0, 1, 2, 3 ]), array([ 0, 1, 2, 3 ]),
        #       array([ 0, 1, 2, 3 ]))
        ax.plot3D(array(self.interptrans[0]), array(self.interptrans[1]),
               array(self.interptrans[2]))
        pylab.show()

    #*********************************************************************************************************
    # Basic file functions
    #*********************************************************************************************************

    def newProject(self):
        self.sceneElements = []
        self.emit(QtCore.SIGNAL("sceneCleared"))
        self.newCursorModel()               ## Includes a 3D Cursor in the scene.
        self.update()

    def autoSave(self):  ## Salva contexto para undo/redo
        print "autoSave"
        self.fileName = "autosave.step"
        output = open(unicode(self.fileName), 'wb')
        cPickle.dump(self.sceneElements,output)
        output.close()

    ## Save presentation content in pickle file format with fileName default.step
    def savePresentation (self):
        self.fileName = "default.step"
        output = open(unicode(self.fileName), 'wb')
        cPickle.dump(self.sceneElements,output)
        output.close()

    ## Save presentation content in pickle file format with a given fileName defined in getSaveFileName dialog.
    def save_As_Presentation (self):
         self.exportStruct("Save Presentation As")

    def exportSlide(self):
        self.exportStruct("Export Slide")

    def exportStruct(self, type):
        fileName = QtGui.QFileDialog.getSaveFileName(self, type, "", "Presentations (*.step)")

        output = open(unicode(fileName), 'wb')
        cPickle.dump(self.sceneElements,output)
        output.close()

    def openPresentation (self):
    ## Restores presentation content from pickle file format and updates hierarchical presentation tree.
        self.newProject()
        self.importStruct("Open Presentation")

    def importSlide(self):
        self.importStruct("Import Slide")

    def importStruct(self,  type):
        fileName = QtGui.QFileDialog.getOpenFileName(self, type, "", "Presentations (*.step)")

        if fileName:
            try:                                            ## Restores presentation to a list.
                self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(Qt.WaitCursor)))
                output = open(unicode(fileName), 'rb')      ## fileName is the path to the file chosen in getOpenFileName dialog.
            except (Exception, ):
                QMessageBox.warning(self, 'Error', 'Open project error.')
            else:
                try:
                    self.sceneElements = cPickle.load(output)

                except (Exception, ):
                    QMessageBox.warning(self, 'Error', 'Read project error.')

                finally:
                    self.fileName = fileName
                    for model in self.sceneElements:        ## Updates hierarchical presentation tree
                        self.emit(QtCore.SIGNAL("presentationLoaded"), (model.groups, model.objName))
                    self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(Qt.ArrowCursor)))
                    output.close()


    #*********************************************************************************************************
    # 3D pre defined objetos - 3dcursor and shapes
    #*********************************************************************************************************

    ## Puts the object in the 3D point where the 3Dcursor is.
    def Cursor3DPosition(self):
        for model in self.sceneElements:        ## Updates hierarchical presentation tree
            if model.objName == "cursor.obj":   ## It's the 3Dcursor object.
                teste = self.sceneElements[0].getTransformation()
                print "cursor matrix ",  teste[0]
                self.tx = teste[0]
                self.ty = teste[1]
                self.tz = teste[2]
                #self.rx = self.sceneElements[model.modelId].rx
                #self.ry = self.sceneElements[model.modelId].ry
                #self.rz = self.sceneElements[model.modelId].rz
                print "model.objName ",model.objName, self.tx, self.ty, self.tz
                #self.sceneElements[-1].setTranslate(self.tx, self.ty, self.tz)
                return self.tx, self.ty, self.tz   # E'return mesmo?

    ## Include the 3D arrow model in the current frame.
    def newArrowModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        newArrow = visualElement("obj/arrow.obj", 9990, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(newArrow)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newArrow.groups, newArrow.objName))
        self.repaint()
        del newArrow
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the 3D sphere model in the current frame
    def newSphereModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        newSphere = visualElement("obj/sphere.obj", 9991, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(newSphere)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newSphere.groups, newSphere.objName))
        self.repaint()
        del newSphere
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the 3D cube model in the current frame
    def newCubeModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        newCube = visualElement("obj/cube.obj", 9992, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(newCube)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newCube.groups, newCube.objName))
        self.repaint()
        del newCube
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the 3D cilynder model in the current frame
    def newCylinderModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        newCylinder = visualElement("obj/cylinder.obj", 9993, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(newCylinder)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newCylinder.groups, newCylinder.objName))
        self.repaint()
        del newCylinder
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the 3D gear model in the current frame
    def newGearModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        newGear = visualElement("obj/gear.obj", 9994, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(newGear)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newGear.groups, newGear.objName))
        self.repaint()
        del newGear
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the 3D star model in the current frame
    def newStarModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        newStar = visualElement("obj/star.obj", 9995, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(newStar)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newStar.groups, newStar.objName))
        self.repaint()
        del newStar
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the clasp model in the current frame ## colchete
    def newClaspModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        new3DCursor = visualElement("obj/clasp.obj", 9996, -1, None, False)
        self.tx, self.ty, self.tz = self.Cursor3DPosition()

        self.sceneElements.append(new3DCursor)
        self.emit(QtCore.SIGNAL("modelLoaded"), (newClasp.groups, newClasp.objName))
        self.repaint()
        del newClasp
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    ## Include the 3D cursor model in the current frame
    def newCursorModel(self):
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(3)))
        new3DCursor = visualElement("obj/cursor.obj", 0, -1, None, False)
        #self.Cursor3DPosition()
        self.sceneElements.append(new3DCursor)
        self.emit(QtCore.SIGNAL("modelLoaded"), (new3DCursor.groups, new3DCursor.objName))
        self.repaint()
        del new3DCursor
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

    def openModel(self):

        fileName = QtGui.QFileDialog.getOpenFileName(self, "Open File", "", "Models (*.obj)")

        if (fileName != ""):
            self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(Qt.WaitCursor)))
            if len(self.sceneElements):

                isCopy = False
                for index, model in enumerate(self.sceneElements):

                    if model.modelPath == fileName:
                        newModel = visualElement(fileName, self.sceneElements[-1].modelId + len(self.sceneElements[-1].groups) + 1, model.modelId, self.sceneElements[index].getGroupNames())
                        isCopy = True
                        break

                if not isCopy:
                    newModel = visualElement(fileName, self.sceneElements[-1].modelId + len(self.sceneElements[-1].groups) + 1, -1, None)

            else:
                newModel = visualElement(fileName, 0, -1, None, False)

            self.sceneElements.append(newModel)

            self.emit(QtCore.SIGNAL("modelLoaded"), (newModel.groups, newModel.objName))
        del newModel
        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(Qt.ArrowCursor)))

    def selectGroup(self, parent, item):

        if ((parent == "") and (item != "")): ##Se nao ha pai, mas ha item, entao e' modelo.
            for model in self.sceneElements: ##Identifica o indice do modelo selecionado na lista de modelos
                if (model.objName == item):
                    self.selectedModel = model.modelId
                    self.selectedGroup = -1
                    break
        else:
            for index, model in enumerate(self.sceneElements): ##Identifica o indice do modelo selecionado na lista de modelos
                if (model.objName == parent):
                    self.selectedModel = model.modelId
                    m_index = index
                    break
            for group in self.sceneElements[m_index].groups: ##Identifica o indice do grupo selecionado
                if (group.groupName == item):
                    self.selectedGroup = group.groupId
                    break
        self.update()

    #def setDoc(self, doc):
    ## *******************************************************************************
    ## * A deletar! Fun??es sobre o modelo de documenta??o descontinuado
    ## *******************************************************************************

    #model, group = self.findSelections()
    #if (model != -1):
    #    if (group != -1):
    #        self.sceneElements[model].groups[group].groupText = doc
    #    else:
    #        self.sceneElements[model].objText = doc

    #def getCurrentDoc(self):
  ##*******************************************************************************
    ## * A deletar! Fun??es sobre o modelo de documenta??o descontinuado
    ## *******************************************************************************

    #model, group = self.findSelections()
    #if (model != -1):
    #    if (group != -1):
    #        return self.sceneElements[model].groups[group].groupText
    #    else:
    #        return self.sceneElements[model].objText

    def textDoc(self, doc):
        #print "doc ", doc
        w, h = doc.size().width(), doc.size().height()
        docImage = QtGui.QImage(w, h, QtGui.QImage.Format_RGB32)
        docBounds = QtCore.QRectF(0, 0, w, h)
        painter = QtGui.QPainter()
        BGColor = QtGui.QColor(255,255,255)

        painter.begin(docImage)

        painter.fillRect(0, 0, w, h, BGColor)
        doc.drawContents(painter, docBounds)
        painter.end()

        if len(self.sceneElements):
            noteId = self.sceneElements[-1].modelId + len(self.sceneElements[-1].groups) + 1
        else:
            noteId = 0
        docImagePath = "docImage" + str(noteId) + ".jpeg"

        docImage.save(docImagePath, "JPEG", -1)
        print "docImage saved"
        newElement = visualElement(docImagePath, noteId, -1, None, True)
        #newElement.setRotate(45, 0, 0)
        newElement.setTranslate(0, 0.5, 0)
        self.sceneElements.append(newElement)
        #self.emit(QtCore.SIGNAL("modelLoaded"), (None, docImagePath))
        del newElement

        """for noteId, note in enumerate(self.sceneNotes):
            if note.image == doc:
                newElem = visualElement(
                self.sceneElements.append(
                break
        if noteId == len(self.sceneNotes)

        newNote = visual
        self.sceneElements.append"""

    def textAnimation(self, doc):

        """
        w, h = doc.size().width(), doc.size().height()
        docImage = QtGui.QImage(w, h, QtGui.QImage.Format_RGB32)
        docBounds = QtCore.QRectF(0, 0, w, h)
        painter = QtGui.QPainter()
        BGColor = QtGui.QColor(255,255,255)

        painter.begin(docImage)

        painter.fillRect(0, 0, w, h, BGColor)
        doc.drawContents(painter, docBounds)
        painter.end()

        if len(self.sceneElements):
            noteId = self.sceneElements[-1].modelId + len(self.sceneElements[-1].groups) + 1
        else:
            noteId = 0
        docImagePath = "docImage" + str(noteId) + ".jpeg"

        docImage.save(docImagePath, "JPEG", -1)
        print "docImage saved"
        """
        #Tem que ter um elementVisual a mais para animacao?? Acho que nao
        """
        docImagePath = doc
        if len(self.sceneElements):
            animId = self.sceneElements[-1].modelId + len(self.sceneElements[-1].groups) + 1
        else:
            animId = 0

        print "docImagePath, animId ", docImagePath, animId
        """

        #Tem que ter um elementVisual a mais para animacao?? Acho que nao
        #newElement = visualElement(docImagePath, animId, -1, None, False)

        #newElement.setRotate(45, 0, 0)
        #newElement.setTranslate(0, 0.5, 0)
        ## Ver newElement 2008-05-02
        #self.sceneElements.append(newElement)  # Nao e um elemento visual.

        ##
        #print "*** animList = animType ",self.sceneElements[-1].animList
        # Incluir informação de animacao na arvore hierarquica
        #Nao e aqui       self.sceneElements[-1].animList = [self.animType,self.initFrame, self.lastFrame]

        self.emit(QtCore.SIGNAL("animationLoaded"), (None, doc))

        #del newElement

        """for noteId, note in enumerate(self.sceneNotes):
            if note.image == doc:
                newElem = visualElement(
                self.sceneElements.append(
                break
        if noteId == len(self.sceneNotes)

        newNote = visual
        self.sceneElements.append"""

    def findSelections(self):
        m_index = g_index = -1
        for index1, model in enumerate(self.sceneElements):

            if (model.modelId == self.selectedModel):
                m_index = index1
                for index2, group in enumerate(model.groups):

                    if (group.groupId == self.selectedGroup):
                        g_index = index2
                        break
                ##g_index = self.selectedGroup - self.selectedModel - 1
                break

        return m_index, g_index

    ## Color edit dialog.
    def changeColor(self):
        white = QtGui.QColor(255,255,255)
        newColor = QtGui.QColorDialog.getColor(white, self)

        if newColor.isValid():

                if self.selectedModel != -1:

                        index_m, index_g = self.findSelections()

                        if self.selectedGroup != -1:

                                self.sceneElements[index_m].groups[index_g].setColor(newColor.red(), newColor.green(), newColor.blue())
                        else:
                                self.sceneElements[index_m].setColor(newColor.red(), newColor.green(), newColor.blue())

    def zoomOut(self):
        if -4.0 > self.eyeZ > -2.0:
                self.eyeZ -= 0.1
        """
        if self.selectedModel != -1:

           index_m, index_g = self.findSelections()

           if self.selectedGroup != -1:
              self.sceneElements[index_m].groups[index_g].setTranslate(0, 0, self.tz)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:
              self.sceneElements[index_m].setTranslate(0, 0, self.tz)
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
           self.update()
        """

    def zoomIn(self):
        if -4.0 > self.eyeZ > -2.0:
            self.eyeZ += 0.1
        """
        if self.selectedModel != -1:

           index_m, index_g = self.findSelections()

           if self.selectedGroup != -1:
              self.sceneElements[index_m].groups[index_g].setTranslate(0, 0, self.tz)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:
              self.sceneElements[index_m].setTranslate(0, 0, self.tz)
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
           self.update()
        """

    def scaleFactor(self, oper):   ## Used to shortcut s and scale button either.
        if oper == 's':   ## minus operation
          #self.sx = self.newpt[0] - self.lastpt[0]
          self.sx = self.sx * 0.9
          self.sy = self.sy * 0.9
          self.sz = self.sz * 0.9
        else: ## add operation
          self.sx = self.sx * 1.1
          self.sy = self.sy * 1.1
          self.sz = self.sz * 1.1

        self.scale()

    def scale(self):
        if self.selectedModel != -1:

           index_m, index_g = self.findSelections()

           if self.selectedGroup != -1:         ## Scales selected group
              self.sceneElements[index_m].groups[index_g].setScale(self.sx, self.sy, self.sz)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:                               ## Scales the hole selected object
              self.sceneElements[index_m].setScale(self.sx, self.sy, self.sz)
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
           self.update()

    #**************************************************************************************************************
    # Transformation routines
    #**************************************************************************************************************

    def translate(self):
        if self.selectedModel != -1:

           index_m, index_g = self.findSelections()

           if self.selectedGroup != -1:
              self.sceneElements[index_m].groups[index_g].setTranslate(self.tx, self.ty, 0.0)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:
              print "self.sceneElements[0] ", self.sceneElements[0]
              self.sceneElements[index_m].setTranslate(self.tx, self.ty, 0.0)
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
           self.update()

    def translateObject (self,event):
        """Mouse drag callback when moving an object in the scene."""

        global startx, starty
        #if self.selectedModel != -1:
        #print " translate object"

        if self.selectedModel != -1:

           index_m, index_g = self.findSelections()

           if self.selectedGroup != -1:
              #m = matrix.glinverse (self.getTransformationMatrix())
              m = matrix.glinverse (self.sceneElements[index_m].groups[index_g].transformation)

              delta = gltransformvector (m,[event.x()-self.startx,
                                             self.starty-event.y(), 0])
              self.sceneElements[index_m].groups[index_g].translate(*delta)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:
              print "self.sceneElements[0] ", self.sceneElements[0]
              m = matrix.glinverse (self.sceneElements[index_m].transformation)

              delta = gltransformvector (m,[event.x()-self.startx,
                                             self.starty-event.y(), 0])
              self.sceneElements[index_m].translate(*delta)
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
           self.update()

        #------------------------------------------------------------------------
        self.startx,self.starty = event.x(),event.y()
        self.updateGL()

   #def addTranslate(self, tx, ty, tz):
    def translateScene(self,  tx,  ty,  yz):

        for model in self.sceneElements:
            model.setTranslate(model.tx + tx, model.ty + ty, model.tz + tz)

    #def rotateScene(self, rx, ry, rz):
    def rotateScene(self, rx, ry, rz):

        for model in self.sceneElements:
            model.setRotate(model.rx + rx, model.ry + ry, model.rz + rz)

    def multScale(self, sx, sy, sz):

	    for model in self.sceneElements:
		    model.setScale(model.sx * sx, model.sy * sy, model.sz * sz)

    def setColor(self, r, g, b):

	    for model in self.sceneElements:
		    model.setColor(r, g, b)

    #********************************************************************************************
    # Finding an'object position in 3D
    #********************************************************************************************
    def pick(self,x,y):
        """Uses the OpenGL selection mechanism for figuring out which object
        lies at screen position (x,y).
        @param x,y: screen position.
        @return: the selection buffer, i.e., a list of tuples (mindepth,
           maxdepth, names), where names is a list of object names -- i.e.,
           collection indices -- with the one on top of the stack last. Thus,
           if names==[3,10], then element 3 of this collection was hit
           and it was itself a collection whose element 10 was hit.
        """
        # Prepare for picking
        glSelectBuffer(100)

        glRenderMode(GL_SELECT)
        viewport = glGetIntegerv (GL_VIEWPORT)
        projmatrix = glGetDoublev (GL_PROJECTION_MATRIX)
        glInitNames()
        glPushName(0)
        glMatrixMode (GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity ()
        glMatrixMode (GL_PROJECTION)
        glPushMatrix ()
        glLoadIdentity ()
        # create 5x5 pixel picking region near cursor location
        gluPickMatrix (x, (viewport[3] - y), 5, 5, viewport);
        glMultMatrixd (projmatrix)

        self.drawScene(True)
        ## self.draw()

        glPopName()
        buffer = glRenderMode(GL_RENDER)
        # Restore modelview
        glMatrixMode (GL_MODELVIEW)
        glPopMatrix ()
        # Restore projection
        glMatrixMode (GL_PROJECTION)
        glPopMatrix ()
        # Process hits
        return list(buffer)

    def pickClosest (self, x, y):           ## SEM USO??
        """Uses the OpenGL selection mechanism for figuring out which object
        lies at screen position (x,y). Similar to pick, but returns only one
        object (the closest one).
        @param x,y: screen position.
        @return: A tuple (obj, z), where obj is the object and z is its z coordinate at
           the pick position. If no object lies at the given position, then
           obj is None."""
        closest = None
        closestZ = 1.0
        for hit in self.pick(x,y):
            print "hit"
            minz, maxz, name = hit
            z = 1.0 * minz / (2**32-1)
            if z < closestZ:
                closestZ,closest = z, self[name[0]]
        return (closest, closestZ)


    def renderPick(self, x, y):
            """Uses the OpenGL selection mechanism for figuring out which models were selected
            lies at screen position (x,y). Similar to pick, but returns only one
            object (the closest one).

            @param x,y: screen position.
            """
            self.sceneRenderSetUp()        ## Tem dentro do draw? mas precisa. Porque?

            ##Prepares for picking
            glSelectBuffer(100)
            glRenderMode(GL_SELECT)
            viewport = glGetIntegerv(GL_VIEWPORT)
            projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
            glInitNames()
            glPushName(0)
            glMatrixMode(GL_PROJECTION)
            glPushMatrix()
            glLoadIdentity()
            ##Creates 5x5 pixel picking region near cursor location
            gluPickMatrix (x, (viewport[3] - y), 5, 5, viewport);
            glMultMatrixd (projMatrix)

            self.drawScene(True)

            buffer = glRenderMode(GL_RENDER)

            ##Restores projection
            glMatrixMode(GL_PROJECTION)
            glPopMatrix()
            ##Processes hits
            picked = []
            for hitRecord in buffer:
                minDepth, maxDepth, names = hitRecord
                picked.append(names[-1]-1)
            print "picked ", picked
            if (picked):
                self.selectedGroup = picked[-1] + 1

                for model in self.sceneElements:
                    if ((model.modelId + len(model.groups)) > self.selectedGroup):
                        for group in range(0, len(model.groups)):
                            if model.groups[group].groupId == self.selectedGroup:
                                self.selectedModel = model.groups[group].parentId
                                selectionName = model.groups[group].groupName

                #self.emit(QtCore.SIGNAL("objectSelected"), (selectionName)) COMENTADO PARA TESTES COM DOCUMENTAÇÃO

            self.update()

            return picked
            #**************************************************************************************************************
    # Mouse controls
    #**************************************************************************************************************

    def defaultMouseMoveEvent (self, event):
        """This mouse motion function does nothing."""
        pass

    def mouseMoveEvent (self, event):
        """Calls an apropriate function to handle mouse move events"""
        self.motionfunc (event)

    ## Records the double click event
    def mouseDoubleClickEvent(self, event):
        print "recurso de interface nao definido para o duplo clique"

    ## Triggered by any mouse click event
    def mouseClickEvent(self, event):
        print "mover cursor 3D"
        self.Cursor3DPosition()     ## Change 3DCursor Position

    def mousePressEvent (self, event):
        """Handles mouse button press events."""

        def screencoords (obj):
            """Returns the screen coordinates of the center of an
            object of the scene."""
            glMatrixMode (GL_MODELVIEW)
            glLoadIdentity()
            glMultMatrixd (self.scene.transformation)       ##VER
            glMultMatrixd (obj.transformation)                   ##VER
            viewport = glGetIntegerv (GL_VIEWPORT)
            projmatrix = glGetDoublev (GL_PROJECTION_MATRIX)
            modelviewmatrix = glGetDoublev (GL_MODELVIEW_MATRIX)

            x,y,z = obj.box.center

            return gluProject (x,y,z,modelviewmatrix,projmatrix,viewport)

        self.startx, self.starty = x,y = event.x(), event.y()

        print "Mouse press - len(self.sceneElements)", len(self.sceneElements)

        if event.buttons() & Qt.LeftButton:         # Associated with scene or object rotation

            self.rotacao = True

            if len(self.sceneElements): ##Se ha elemento 3D na cena, testa a selecao por clique.
                print "x, y ", x,  y
                #self.picked = self.pickClosest(x,y)[0]        #Esperanca   self.picked = self.scene.pickClosest(x,y)[0]
                self.picked = self.renderPick(x,y)
                #print "self.picked ", self.picked

            print "self.picked ", self.picked
            #if self.picked is None:  ## Transformation will be applied to all scene
            if not self.picked:  ## Transformation will be applied to all scene               #if self.picked is None:  ## Transformation will be applied to all scene
                print "rotateScene"
                center = matrix.gltransformpoint (self.sceneElements.transformation,
                                                  self.sceneElements.box.center)

                self.arcball = ArcBall (center, self.sceneElements.box.radius())
                self.motionfunc = self.rotateScene
            else:   ## Transformation will be applied to the selected object
                print "rotateObject"

                #Tirei self.arcball = ArcBall (screencoords(self),
                #                        self.picked.box.radius())
                """ Obter center side do objeto selecionado.
                    com modelId em self.picked
                """
                self.arcball = ArcBall (self.coords,
                                            self.radius)
                self.motionfunc = self.rotateObject

        elif event.buttons() & Qt.RightButton:      # Associated with scene or object translation
            #Esperanca self.picked = self.scene.pickClosest(x,y)[0]
            if len(self.sceneElements): ##Se ha elemento 3D na cena, testa a selecao por clique.
                #self.picked = self.pickClosest(x,y)[0]        #self.picked = self.renderPick(x,y)                      #Esperanca
                self.picked = self.renderPick(x,y)


            #if self.picked is None:  ## Transformation will be applied to all scene
            if not self.picked:  ## Transformation will be applied to all scene

                print "translateScene"
                #self.motionfunc = self.addTranslate
                self.motionfunc = self.translateScene
            else:
                print "translateObject"
                self.motionfunc = self.translateObject

        elif event.buttons() & Qt.MidButton:        # Associated with scene or object scale

            #Esperanca self.picked = self.scene.pickClosest(x,y)[0]
            if len(self.sceneElements): ##Se ha elemento 3D na cena, testa a selecao por clique.
                #self.picked = self.pickClosest(x,y)[0]        #self.picked = self.renderPick(x,y)                      #Esperanca
                self.picked = self.renderPick(x,y)


            #if self.picked is None:  ## Transformation will be applied to all scene
            if not self.picked:  ## Transformation will be applied to all scene

                print "scaleScene"
                self.motionfunc = self.scaleScene
            else:
                print "scaleObject"
                self.motionfunc = self.scaleObject




        elif event.buttons() & Qt.RightButton:
            # Associated with scene or object translation
            if len(self.sceneElements): ##Se ha elemento 3D na cena, testa a selecao por clique.
                self.picked = self.renderPick(x,y)
                print "self.picked ", self.picked

            #Esperanca self.picked = self.scene.pickClosest(x,y)[0]
            #if self.picked is None:  ## Transformation will be applied to all scene
            if self.picked == -1:  ## Transformation will be applied to all scene
                #self.motionfunc = self.translateScene
                self.motionfunc = self.translateScene
            else:
                self.motionfunc = self.translateObject

        elif event.buttons() & Qt.MidButton:
            if len(self.sceneElements): ##Se ha elemento 3D na cena, testa a selecao por clique.
                self.picked = self.renderPick(x,y)
                print "self.picked ", self.picked

            #Esperanca self.picked = self.scene.pickClosest(x,y)[0]
            if self.picked is None:  ## Transformation will be applied to all scene
                self.motionfunc = self.scaleScene
            else:
                self.motionfunc = self.scaleObject

    def mouseReleaseEvent (self, event):
        """Handles mouse button release events."""
        self.motionfunc = self.defaultMouseMoveEvent

        ##Esperanca self.scene.computeBoundingBox()

        ##def computeBoundingBox(self):    ## Ficava na classe graphicobjectcollection
        """Recomputes this collection's bounding box. Should be called
        before using the bounding box if it is not certain whether any of the
        elements' boxes have been modified.
        """
        allPoints = []
        from scene import matrix
        for obj in self.sceneElements:
            if isinstance(obj,GraphicObject):
                allPoints += map(lambda p: matrix.gltransformpoint (obj.transformation, p),
                                 obj.box.vertices())
        self.box = BoundingBox.fromPoints(allPoints)




        """
        if self.selectedModel != -1: ## computeBoundingBox

           index_m, index_g = self.findSelections()

           if self.selectedGroup != -1:
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].transformation)
           else:
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].transformation)
           self.update()

        self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape(0)))

        self.updateGL()
        """

    # Escrever texto na tela com a rotina do Victor
    def drawText( self, value, x,y,  windowHeight, windowWidth, step = 18 ):
        """Draw the given text at given 2D position in window"""
        print "value ", value

        glMatrixMode(GL_PROJECTION);
        # For some reason the GL_PROJECTION_MATRIX is overflowing with a single push!
        # glPushMatrix()
        matrix = glGetDouble( GL_PROJECTION_MATRIX )

        glLoadIdentity();
        glOrtho(0.0, windowHeight or 32, 0.0, windowWidth or 32, -1.0, 1.0)
        glMatrixMode(GL_MODELVIEW);
        #glPushMatrix();
        glLoadIdentity();
        glRasterPos2i(x, y);
        lines = 0
        for character in value:
            print "character", character
            if character == '\n':
                glRasterPos2i(x, y-(lines*18))
            else:
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ord(character))   # Cmd nao funciona
        glPopMatrix()
        glMatrixMode(GL_PROJECTION)
        # For some reason the GL_PROJECTION_MATRIX is overflowing with a single push!
        #glPopMatrix()
        glLoadMatrixd( matrix ) # should have un-decorated alias for this...
        glMatrixMode(GL_MODELVIEW);

    def delSceneElement(self):
            if self.selectedModel == 0:     ## 3D Cursor can't be deleted.
                print "3D Cursor can't be deleted."
                return
            if self.selectedModel != -1:
               index_m, index_g = self.findSelections()
               if self.selectedGroup != -1:
                  self.emit(QtCore.SIGNAL("modelDeleted"))
                  del self.sceneElements[index_m].groups[index_g]
                  #self.emit(QtCore.SIGNAL("modelDeleted"), (index_m,index_g))
                  #self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())

               else:
                  #self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
                  #self.emit(QtCore.SIGNAL("modelDeleted"), (index_m,0))
                  del self.sceneElements[index_m]
                  self.emit(QtCore.SIGNAL("modelDeleted"))

    def wheelControl(self): ## Controls increasing/decreasing of distance from screen commanded from mouse wheel.

        if self.selectedModel != -1:
           index_m, index_g = self.findSelections()
           if self.selectedGroup != -1:
              self.sceneElements[index_m].groups[index_g].setTranslate(0, 0, self.tz)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:
              self.sceneElements[index_m].setTranslate(0, 0, self.tz)
              self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
           self.update()


    def wheelEvent(self, event):
        if event.delta() > 0:    ## Wheel control - increase distance of the objects about the camera.
           self.eyeZ= self.eyeZ + 0.1
           #self.wheelControl()

        elif event.delta() < 0: ## Wheel control - decrease distance of the objects about the camera.
            self.eyeZ= self.eyeZ - 0.1
            #self.wheelControl()
        self.repaint()
        #self.update()


    #*************************************************************************************************************
    # Key controls
    #*************************************************************************************************************

    def copy(self):
        if os.name == "nt":                      ## Windows operation system.
            self.tempBuffer = cPickle.dumps(self.sceneElements)
            print "self.tempBuffer ", self.tempBuffer
        else:    ## Grava o buffer em disco, permitindo restauracao em outra sessao do programa.
            self.fileName = "tempBuffer.step"
            output = open(unicode(self.fileName), 'wb')
            cPickle.dump(self.sceneElements,output)
            output.close()

    def cut(self):
        self.copy()    ## Copia objetos selecionados para area temporaria
        self.delSceneElement()    ## Retira objetos copiados da cena

    def paste(self):

        if os.name == "nt":                      ## Windows operation system.
            self.sceneElements =cPickle.loads(self.tempBuffer)
            print "self.tempBuffer ", self.tempBuffer
        else:    ## Grava o buffer em disco, permitindo restauracao em outra sessao do programa.
            self.fileName = "tempBuffer.step"
            output = open(unicode(self.fileName), 'rb')
            self.sceneElements = cPickle.load(output)
            output.close()

    def keyMovement(self):  ## Arrow movement (left or right)

        if self.selectedModel != -1:
           index_m, index_g = self.findSelections()
           if self.selectedGroup != -1:
              self.sceneElements[index_m].groups[index_g].setTranslate(self.tx, self.ty, self.tz)
              self.sceneElements[index_m].groups[index_g].box = self.sceneElements[index_m].groups[index_g].box.transform(self.sceneElements[index_m].groups[index_g].getTransformationMatrix())
           else:
              self.sceneElements[index_m].setTranslate(self.tx, self.ty, self.tz)
              if self.selectedModel != 0:   ## Create boundingBox to all selected objects, expect for 3D cursor
                self.sceneElements[index_m].box = self.sceneElements[index_m].box.transform(self.sceneElements[index_m].getTransformationMatrix())
        self.update()

    def keyPressEvent(self, event):

        self.key = QString()

        if event.key() == Qt.Key_Delete: ##Delete selected object or group
            self.delSceneElement()

        elif event.key() == QtCore.Qt.Key_Left:
            self.tx += 0.1
            self.keyMovement()

        elif event.key() == QtCore.Qt.Key_Right:
            self.tx -= 0.1
            self.keyMovement()

        elif event.key() == QtCore.Qt.Key_Up:
            self.tz = self.tz + 0.1
            self.wheelControl()         ## Does the same procedure as event.mouse_wheel() > 0

        elif event.key() == QtCore.Qt.Key_Down:
            self.tz = self.tz - 0.1
            self.wheelControl()          ## Does the same procedure as event.mouse_wheel() < 0:

        elif event.modifiers() & Qt.AltModifier:     ## Keyboard shortcut to scaling
            print "alt key"
            if event.text() == 's':         ## Diminishes selected objects
                self.scaleFactor('s')
                self.scale()
            elif event.text() == 'S':
                self.scaleFactor('S')       ## Expands selected objects
                self.scale()

        elif event.key() == '+':                ## Keyboard shortcut to wheel control - increase position along the Z axis
            self.tz = self.tz + 0.1
            self.wheelControl()

        elif event.key() == '-':                ## Keyboard shortcut to wheel control - decrease position along the Z axis
            self.tz = self.tz + 0.1
            self.wheelControl()

        elif event.modifiers() & Qt.ControlModifier:
            print "control key" ## Evento sem funcionalidade ainda

        elif event.modifiers() & Qt.ShiftModifier:
            print "shift key" ## Shitf key pressed will be used to indicate multiple elections.

        elif event.text() == "a": ##Wait sceneTime time to display screen objects
            print "Keyboard shortcut a"

        elif event.text() == "d": ##Wait sceneTime time to hide screen objects
            print "Keyboard shortcut d"

        elif event.text() == "f": ##Move objects far from camera
            print "Keyboard shortcut f"

        elif event.text() == "c": ##Cut selected objects to clipboard
            print "Keyboard shortcut cut object"
            ## Futuro: Para o objeto / grupo selecionado
            self.cut()

        elif event.text() == "d": ##Duplicate selected objects from clipboard
            print "Keyboard shortcut to duplicate object"
            self.copy()

        elif event.text() == "p": ##Past clipboard content to scene
            print "Keyboard shortcut to past clipboard content to scene"
            self.paste()


        self.update()

